package org.mybatis.generator.plugins;

import org.mybatis.generator.api.IntrospectedColumn;
import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.PluginAdapter;
import org.mybatis.generator.api.dom.java.FullyQualifiedJavaType;
import org.mybatis.generator.api.dom.java.Interface;
import org.mybatis.generator.api.dom.java.JavaVisibility;
import org.mybatis.generator.api.dom.java.Method;
import org.mybatis.generator.api.dom.java.Parameter;
import org.mybatis.generator.api.dom.java.TopLevelClass;
import org.mybatis.generator.api.dom.xml.Document;
import org.mybatis.generator.api.dom.xml.TextElement;
import org.mybatis.generator.api.dom.xml.XmlElement;
import org.mybatis.generator.codegen.mybatis3.ListUtilities;
import org.mybatis.generator.codegen.mybatis3.MyBatis3FormattingUtilities;
import org.mybatis.generator.config.Context;
import org.mybatis.generator.utils.JavaMapperGeneratorHelper;
import org.mybatis.generator.utils.XMLMapperGeneratorHelper;

import java.util.List;
import java.util.Set;

/**
 * <b><code>BatchUpdatePlugin</code></b>
 * <p/>
 * Description: 批量更新
 * <p/>
 * <b>Creation Time:</b> 2020/06/10.
 */
public class BatchUpdatePlugin extends PluginAdapter {

	private final static String BATCH_UPDATE = "batchUpdate";

	private final static String PARAMETER_NAME = "recordList";

	@Override
	public boolean validate(List<String> list) {
		return true;
	}

	@Override
	public boolean clientGenerated(Interface interfaze, TopLevelClass topLevelClass,
			IntrospectedTable introspectedTable) {
		if (introspectedTable.getTargetRuntime() == IntrospectedTable.TargetRuntime.MYBATIS3) {
			clientBatchUpdateMethodGenerated(interfaze, introspectedTable, context);
		}
		return super.clientGenerated(interfaze, topLevelClass, introspectedTable);
	}

	@Override
	public boolean sqlMapDocumentGenerated(Document document, IntrospectedTable introspectedTable) {
		if (introspectedTable.getTargetRuntime() == IntrospectedTable.TargetRuntime.MYBATIS3) {
			sqlMapBatchUpdateElementGenerated(document, introspectedTable);
		}
		return super.sqlMapDocumentGenerated(document, introspectedTable);
	}

	private void clientBatchUpdateMethodGenerated(Interface interfaze, IntrospectedTable introspectedTable,
			Context context) {
		Set<FullyQualifiedJavaType> importedTypes = JavaMapperGeneratorHelper
				.importedBaseTypesGenerator(introspectedTable);

		FullyQualifiedJavaType listParameterType = FullyQualifiedJavaType.getNewListInstance();
		listParameterType.addTypeArgument(introspectedTable.getRules().calculateAllFieldsClass());

		Method batchUpdateMethod = JavaMapperGeneratorHelper.methodGenerator(BATCH_UPDATE, JavaVisibility.DEFAULT,
				FullyQualifiedJavaType.getIntInstance(),
				new Parameter(listParameterType, PARAMETER_NAME, "@Param(\"" + PARAMETER_NAME + "\")"));

		context.getCommentGenerator().addGeneralMethodComment(batchUpdateMethod, introspectedTable);

		interfaze.addImportedTypes(importedTypes);
		interfaze.addMethod(batchUpdateMethod);
	}

	public void sqlMapBatchUpdateElementGenerated(Document document, IntrospectedTable introspectedTable) {
		String tableName = introspectedTable.getFullyQualifiedTableNameAtRuntime();
		List<IntrospectedColumn> columnList = ListUtilities
				.removeIdentityAndGeneratedAlwaysColumns(introspectedTable.getAllColumns());
		// primaryKey的JDBC名字
		String primaryKeyName = introspectedTable.getPrimaryKeyColumns().get(0).getActualColumnName();

		// primaryKey的JAVA变量
		String primaryKeyParameterClause = MyBatis3FormattingUtilities
				.getParameterClause(introspectedTable.getPrimaryKeyColumns().get(0), "item.");

		XmlElement updateXmlElement = XMLMapperGeneratorHelper.baseElementGenerator(XMLMapperGeneratorHelper.UPDATE,
				BATCH_UPDATE, FullyQualifiedJavaType.getNewListInstance().getFullyQualifiedName(), null, null);

		updateXmlElement.addElement(new TextElement(String.format("update %s ", tableName)));

		XmlElement trimElement = XMLMapperGeneratorHelper.baseTrimElement("set", null, ",");

		for (int i = 0; i < columnList.size(); i++) {

			IntrospectedColumn introspectedColumn = columnList.get(i);

			String columnName = introspectedColumn.getActualColumnName();

			String columnJavaTypeName = introspectedColumn.getJavaProperty("item.");

			String parameterClause = MyBatis3FormattingUtilities.getParameterClause(introspectedColumn, "item.");

			String ifSql = String.format("when %s then %s", primaryKeyParameterClause, parameterClause);
			XmlElement ifElement = XMLMapperGeneratorHelper.baseIfJudgeElementGen(columnJavaTypeName, ifSql, false);

			String ifNullSql = String.format("when %s then %s", primaryKeyParameterClause,
					tableName + "." + columnName);
			XmlElement ifNullElement = XMLMapperGeneratorHelper.baseIfJudgeElementGen(columnJavaTypeName, ifNullSql,
					true);

			XmlElement foreachElement = XMLMapperGeneratorHelper.baseForeachElementGenerator(PARAMETER_NAME, "item",
					"index", null);
			foreachElement.addElement(ifElement);
			foreachElement.addElement(ifNullElement);

			XmlElement caseTrimElement = XMLMapperGeneratorHelper
					.baseTrimElement(columnName + " =case " + primaryKeyName, "end,", null);
			caseTrimElement.addElement(foreachElement);

			trimElement.addElement(caseTrimElement);
		}

		updateXmlElement.addElement(trimElement);

		XmlElement foreachElement = XMLMapperGeneratorHelper.baseForeachElementGenerator(PARAMETER_NAME, "item",
				"index", ",");
		foreachElement.addElement(new TextElement(primaryKeyParameterClause));

		updateXmlElement.addElement(new TextElement(String.format("where %s in (", primaryKeyName)));

		updateXmlElement.addElement(foreachElement);

		updateXmlElement.addElement(new TextElement(")"));

		document.getRootElement().addElement(updateXmlElement);
	}

}